package org.example.collection;

import org.junit.Test;

import java.util.Stack;
import java.util.concurrent.TimeUnit;

/**
 * Stack 继承自 Vector，实现一个后进先出的堆栈。Vector、Hashtable、Stack 都是线程安全的.
 * 这个栈的意思相当于只有一个口子的管子，先丢进去的在底部，后丢进去的在上面，先进后出。
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2021/8/6 9:34
 */
@SuppressWarnings("all")
public class StackTest {

    /**
     * E push(E item) ：添加元素
     * boolean empty()：测试此堆栈是否为空
     * synchronized E pop() ：移除此堆栈顶部的对象，并将该对象作为此函数的值返回。此堆栈顶部的对象（向量的最后一项），如果此堆栈为空，则引发EmptyStackException
     * synchronized E peek() ：查看此堆栈顶部的对象，而不将其从堆栈中移除。如果此堆栈为空，则引发EmptyStackException。
     */
    @Test
    public void testStack1() {
        Stack<Integer> stack = new Stack<>();
        for (int i = 1; i <= 10; i++) {
            stack.push(i);
        }
        System.out.println(stack);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

        while (!stack.empty()) {
            Integer pop = stack.pop();
            System.out.print(pop + "\t,");//10	,9	,8	,7	,6	,5	,4	,3	,2	,1	,
        }
    }


    /**
     * 验证 Stack 的并发线程安全
     * 1、假设有 1000 个号(total=1000)，由50个窗口(windows=50)同时卖，每个窗口卖规定卖20个号.
     * 2、最后得结果如果是 Stack 为空，且各个线程没有卖重复的号，则说明并发正常.
     * 3、如果换成 ArrayList ，则立马出现错误数据.
     */
    @Test
    public void testStack2() {
        Stack<Integer> stack = new Stack<>();
        int total = 1000;
        int windows = 50;
        int count = 20;

        for (int i = 1; i <= total; i++) {
            stack.push(i);
        }

        for (int i = 1; i <= windows; i++) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        int i = 0;
                        while (i++ < count) {
                            Integer pop = stack.pop();
                            System.out.println(Thread.currentThread().getName() + ":" + pop);
                            Thread.sleep(200);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        try {
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(stack);//[]
    }

}
